A Cloudflare Worker that detects disposable/temporary email domains and invalid TLDs, exposed as a fast JSON API. Ships 122K+ domains in a ~291KB binary bloom filter — one runtime dependency (tldts), no external calls, pure edge compute. Includes a clean web UI at / for quick checks and /llms.txt for AI agent discovery.
Live deployment: throwaway.sslboard.com
At build time, npm run build:filter reads the disposable-email-domains list (122K+ entries) and compiles it into a bloom filter — a space-efficient probabilistic data structure. The filter is stored as a raw .bin file and loaded via Cloudflare Workers' Data rule as an ArrayBuffer at module load time. No base64, no encoding overhead, zero decode cost.
At request time, tldts parses the domain to determine whether the TLD is a real, ICANN-recognized public suffix. This catches addresses like user@fake.notarealtld that have no chance of receiving mail.
| Property | Value |
|---|---|
| Items | ~122K domains |
| Filter size | ~291 KB |
| False positive rate | ~0.1% (1 in 1,000) |
| False negatives | Zero |
| Hash functions | 10 (double-hashing from 2 cyrb53 hashes) |
Why 0.1% false positives are acceptable: Disposable email signups are low-quality. A false positive means one legitimate user retries with a different address — a minor inconvenience. False negatives (letting disposables through) are the real problem, and bloom filters guarantee zero false negatives.
Minimal web UI — single input field to check emails. Shows three verdicts: LEGITIMATE, DISPOSABLE, or INVALID.
Check a single email address.
{
"email": "user@mailinator.com",
"domain": "mailinator.com",
"valid_tld": true,
"disposable": true
}Check a single domain.
{ "domain": "mailinator.com", "valid_tld": true, "disposable": true }Batch check emails or domains.
Emails:
{
"emails": ["user@mailinator.com", "john@gmail.com", "test@fake.notarealtld"]
}Response:
{
"results": [
{
"email": "user@mailinator.com",
"domain": "mailinator.com",
"valid_tld": true,
"disposable": true
},
{ "email": "john@gmail.com", "domain": "gmail.com", "valid_tld": true, "disposable": false },
{
"email": "test@fake.notarealtld",
"domain": "fake.notarealtld",
"valid_tld": false,
"disposable": false
}
]
}Domains:
{
"domains": ["mailinator.com", "gmail.com"]
}Response:
{
"results": [
{ "domain": "mailinator.com", "valid_tld": true, "disposable": true },
{ "domain": "gmail.com", "valid_tld": true, "disposable": false }
]
}Returns filter metadata.
{
"itemCount": 121570,
"bitCount": 2330512,
"hashCount": 14,
"byteSize": 291314,
"falsePositiveRate": 0.0001
}Machine-readable API documentation for AI agents. Plain text markdown.
| Field | Type | Meaning |
|---|---|---|
valid_tld |
boolean | true if the domain ends in a real ICANN-recognized TLD. false means the address can't receive mail. |
disposable |
boolean | true if the domain is in the disposable-email blocklist. Only meaningful when valid_tld is true. |
valid_tld: false→ reject — domain is not realvalid_tld: true+disposable: true→ reject — known throwaway providervalid_tld: true+disposable: false→ accept — looks legitimate
All errors return {"error": "message"} with appropriate status codes:
| Status | Meaning |
|---|---|
400 |
Missing/invalid parameters or body |
404 |
Unknown path |
405 |
Unsupported HTTP method |
- Synchronous — no I/O, no external API calls, no KV lookups
- Microsecond responses — bloom filter lookup is pure arithmetic
- Zero cold-start overhead — filter loaded as a
Uint8Arrayat module load time - One runtime dependency —
tldtsfor TLD validation (bundled by Wrangler)
git clone <this-repo>
cd throwaway-worker
npm install
npm run build:filter # Generate bloom filter from disposable domain list
npm run dev # Local development
npm run deploy # Deploy to Cloudflare- A Cloudflare account
- Wrangler CLI (installed as a dev dependency)
If you want to update the domain list:
npm run build:filterThis re-reads the disposable-email-domains package and writes fresh src/generated/filter.bin and src/generated/filter-meta.ts files.
MIT — by the people at SSLBoard.com